

function searchDex(deepSearch) {
var result = [];
Process.enumerateRanges('r--').forEach(function (range) {
    try {
        Memory.scanSync(range.base, range.size, "64 65 78 0a 30 ?? ?? 00").forEach(function (match) {
            if (range.file && range.file.path && (range.file.path.startsWith("/data/dalvik-cache/") || range.file.path.startsWith("/system/"))) {
                return;
            }
            console.log("64 65 \t")
            var dex_size = get_dex_real_size(match.address, range.base, range.base.add(range.size));
            result.push({
                "addr": match.address,
                "size": dex_size
            });
            var max_size = range.size - match.address.sub(range.base).toInt32();

            if (deepSearch && max_size != dex_size) {
                result.push({
                    "addr": match.address,
                    "size": max_size
                });
            }


        });

        if (deepSearch) {
            Memory.scanSync(range.base, range.size, "70 00 00 00").forEach(function (match) {
                var dex_base = match.address.sub(0x3C);

                if (dex_base < range.base) {
                    return;
                }

                if (dex_base.readCString(4) != "dex\n" ) {
                    // console.log("70 \t",JSON.stringify(range))
                    if (verify(dex_base,range,true)){
                        var real_dex_size = get_dex_real_size(dex_base, range.base, range.base.add(range.size));
                        console.log("real_dex_size",real_dex_size)
                        if (!verify_ids_off(dex_base, real_dex_size)) {
                            return;
                        }
                        var max_size = range.size - dex_base.sub(range.base).toInt32()

                        if (max_size != real_dex_size) {
                            result.push({
                                "addr": dex_base,
                                "size": max_size
                            });
                        }else{
                            result.push({
                                "addr": dex_base,
                                "size": max_size
                            });
                        }

                    }
                }
            });
        } else {


        }
    } catch (e) {
    }
});
console.log("result",JSON.stringify(result))
return result;
}

function verify_ids_off(dexptr, dex_size) {
    var string_ids_off = dexptr.add(0x3C).readUInt();
    var type_ids_off = dexptr.add(0x44).readUInt();
    var proto_ids_off = dexptr.add(0x4C).readUInt();
    var field_ids_off = dexptr.add(0x54).readUInt();
    var method_ids_off = dexptr.add(0x5C).readUInt();
    return string_ids_off < dex_size && string_ids_off >= 0x70 && type_ids_off < dex_size && type_ids_off >= 0x70 && proto_ids_off < dex_size && proto_ids_off >= 0x70 && field_ids_off < dex_size && field_ids_off >= 0x70 && method_ids_off < dex_size && method_ids_off >= 0x70;
}
function get_dex_real_size(dexptr, range_base, range_end) {
    var dex_size = dexptr.add(0x20).readUInt(); // 0x20 32  file_size
    var maps_address = get_maps_address(dexptr, range_base, range_end); // map_list 地址

    if (!maps_address) {
        return dex_size;
    }

    var maps_end = get_maps_end(maps_address, range_base, range_end);

    if (!maps_end) {
        return dex_size;
    }

    return maps_end.sub(dexptr).toInt32();
}

function verify(dexptr, range, enable_verify_maps) {
    if (range != null) {
        var range_end = range.base.add(range.size); // verify header_size

        if (dexptr.add(0x70) > range_end) {
            return false;
        }

        if (enable_verify_maps) {
            var maps_address = get_maps_address(dexptr, range.base, range_end);

            if (!maps_address) {
                return false;
            }

            var maps_end = get_maps_end(maps_address, range.base, range_end);

            if (!maps_end) {
                return false;
            }

            return verify_by_maps(dexptr, maps_address);
        } else {
            return dexptr.add(0x3C).readUInt() === 0x70;
        }
    }

    return false;
}
function verify_by_maps(dexptr, mapsptr) {
            // mapsptr map 的地址
            // dexptr dex_base  range.base+0x3c 0x3c=60
            var maps_offset = dexptr.add(0x34).readUInt();  // 0x34=52  map_off map偏移地址  base+0x34=map绝对地址  readUInt 从该内存位置读取
            var maps_size = mapsptr.readUInt(); // readUInt 从该内存位置读取 map的值--size

            for (var i = 0; i < maps_size; i++) {
                var item_type = mapsptr.add(4 + i * 0xC).readU16();
                // 4
                // 4 + 12 16
                // 4 + 24  28
                // 4+ 36  40
                // 先查看map_list定义格式
                // size	uint	      列表的大小（以条目数表示）
                // list	map_item[size]	列表的元素
                // map_list	TYPE_MAP_LIST	0x1000	4 + (item.size * 12)

                if (item_type === 4096) {
                    var map_offset = mapsptr.add(4 + i * 0xC + 8).readUInt();
                    //  4 + 12 +8   4+20
                    //  4 + 24 +8   4+32
                    //  4 + 36 +8   4+44
                    //  4 + 48 +8   4+56
                    if (maps_offset === map_offset) {
                        return true;
                    }
                }
            }

            return false;
        }

function get_maps_end(maps_address, range_base, range_end) {
            var maps_size = maps_address.readUInt();


            if (maps_size < 2 || maps_size > 50) {
                return null;
            }
            // console.log("maps_size>:",maps_size)

            var maps_end = maps_address.add(maps_size * 0xC + 4);

            if (maps_end < range_base || maps_end > range_end) {
                return null;
            }

            return maps_end;
}

function get_maps_address(dex_base, range_base, range_end) {
    var maps_offset = dex_base.add(0x34).readUInt(); // 0x34 map_off 偏移地址  readUInt 获取map_list的偏移地址
    // console.log("maps_offset:\t",maps_offset)
    if (maps_offset === 0) {
        return null;
    }

    var maps_address = dex_base.add(maps_offset);

    if (maps_address < range_base || maps_address > range_end) {
                return null;
            }

    return maps_address;

}

// setTimeout(searchDex,1000,true)
// searchDex(true)
// adb forward tcp:8888 tcp:8888

// frida -H 127.0.0.1:8888 -f com.google.android.apps.maps  -l dexdump.js --no-pause
// frida -H 127.0.0.1:8888 -f com.qiyi.video -l dexdump.js --no-pause
// frida -H 127.0.0.1:8888 -f com.qiyi.video -l agent.js --no-pause
// frida-dexdump  -H 127.0.0.1:8888 -d -f com.qiyi.video


var savepath="/data/local/tmp/3/";


function savedex(dexbytes,dexpath) {
    Java.perform(function () {

        var FileOutputStream = Java.use("java.io.FileOutputStream");
        var File = Java.use("java.io.File");
        var fileobj = File.$new(dexpath);
        var fileoutputobj = FileOutputStream.$new(fileobj);
        fileoutputobj.write(dexbytes);
        fileoutputobj.close();



    })
}


function reads(addr,size) {
    var content= ptr(addr).readByteArray(size);
    return content
}


function save() {
   Java.perform(function () {
     var result = searchDex(true);
        for (var i=0;i<result.length;i++){
            var addr = result[i].addr;
            var size = result[i].size;
            console.log(JSON.stringify(result[i]))
            var content= ptr(addr).readByteArray(size);
            var dexpath="/sdcard/"+"1_"+size+".dex";
            // savedex(content,dexpath)
            // write_mes_2(dexpath,content)
        }
   })
}

function write_mes_1() {
    //frida 的api来写文件
    var file = new File("/sdcard/test.txt", "w");
    file.write("Hello Word!");
    file.flush();
    file.close();
}

rpc.exports = {
    write1:function () {
    write_mes_1()
    },
    secdex:function (s) {
        var s = searchDex(true)
        return s;
    },
    readm:function (addr,size) {
        var content = reads(addr,size)
        return content
    },
    test:function () {
         // 获取相应so文件中函数地址
        var resolver = new ApiResolver("module");
        // var lib="*libssl*";
        var lib="*";
        var name="SSL_read";
        var matches = resolver.enumerateMatchesSync("exports:" + lib + "!" + name);
        console.log("hook_test",JSON.stringify(matches))
    }


}